package com.example.clientmiviamoviego4;

import java.util.ArrayList;
import java.util.concurrent.ExecutionException;

import android.app.ActionBar;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.support.v4.widget.DrawerLayout;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

/**
 * Activity che gestisce la schermata principale dell'app.
 * 
 * @author Gang of Four
 * 
 */
public class MainActivity extends Activity implements
		NavigationDrawerFragment.NavigationDrawerCallbacks,
		SettingsFragment.OnAttachedFragment, ErrorFragment.OnConnectedListener {

	/**
	 * Fragment che gestisce i comportament, le interazioni e la presentazione
	 * del navigation drawer.
	 */
	private NavigationDrawerFragment mNavigationDrawerFragment;
	/**
	 * Usato per memorizzare l'ultimo titolo della schermata visualizzata.
	 */
	private CharSequence mTitle;

	/**
	 * ID relativo al fragment di Credits.
	 * */
	private final int CREDITS_FRAGMENT = 0;
	/**
	 * ID relativo all'activity di visualizzazione della lista di film.
	 * */
	private final int LIST_VIEW_ACTIVITY = 1;
	/**
	 * ID relativo al fragment di Search.
	 * */
	private final int SEARCH_FRAGMENT = 2;
	/**
	 * ID relativo al fragment di Settings.
	 * */
	private final int SETTINGS_FRAGMENT = 3;
	/**
	 * Lista completa dei generi di film disponibili sul server.
	 * */
	private ArrayList<ParcelableMovieType> prefList;
	/**
	 * Lista dei generi di film selezionati dall'utente come preferiti.
	 * */
	private ArrayList<ParcelableMovieType> myPrefList;
	/**
	 * Boolean indicante che � stata effettuata la pressione del tasto "back".
	 * */
	private boolean backButtonPressed;
	/**
	 * Toast utilizzato per la visualizzazione di messaggi da rendere evidenti
	 * all'utente.
	 * */
	private Toast toast;
	/**
	 * Context dell'applicazione.
	 * */
	private Context ctx;
	/**
	 * Stringa indicante l'URL relativo all'indirizzo IP del server.
	 * */
	private String basePath;
	/**
	 * Stringa indicante l'username dell'utente che sta attualmente utilizzando
	 * l'app.
	 * */
	String username;
	/**
	 * Intero indicante l'ultima posizione selezionata all'interno del
	 * navigation drawer.
	 * */
	private int last_position;
	/**
	 * Booleano indicante se il server risulta attivo o meno.
	 * */
	boolean server_available = true;

	/**
	 * Metodo richiamato quando l'activity viene creata per la prima volta.
	 * Gestisce il lancio del servizio relativo alle notifiche associate ad un
	 * determinato utente, e le situazioni relative alla corretta verifica della
	 * disponibilit� del server.
	 * */
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		Intent intent = getIntent();
		basePath = intent.getStringExtra("basePath");
		myPrefList = intent.getParcelableArrayListExtra("prefChecked");

		setContentView(R.layout.activity_main);
		ctx = getApplicationContext();
		SharedPreferences prefs = PreferenceManager
				.getDefaultSharedPreferences(MainActivity.this);
		username = prefs.getString("username", null);
		try {
			server_available = new LoadSettings().execute(username).get();
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}
		mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager()
				.findFragmentById(R.id.navigation_drawer);

		mNavigationDrawerFragment.setUp(R.id.navigation_drawer,
				(DrawerLayout) findViewById(R.id.drawer_layout));
		last_position = 0;

		Intent inte = new Intent(this, UpdateNewsService.class);
		inte.putExtra("basePath", basePath);
		startService(inte);
	}

	/**
	 * Metodo chiamato all'atto della selezione di una voce all'interno del
	 * navigation drawer.
	 * */
	@Override
	public void onNavigationDrawerItemSelected(int position) {

		FragmentManager fragmentManager = getFragmentManager();
		Fragment currentFragment = null;

		if (position == CREDITS_FRAGMENT) {
			currentFragment = CreditsFragment
					.newInstance(getString(R.string.title_credits_go4));
			fragmentManager.beginTransaction()
					.replace(R.id.container, currentFragment).commit();
		} else {
			if (server_available) {
				switch (position) {
				case LIST_VIEW_ACTIVITY:

					Intent intent = new Intent(MainActivity.this,
							ViewListFilmFragmentActivity.class);
					intent.putExtra("basePath", basePath);
					startActivity(intent);
					break;
				case SEARCH_FRAGMENT:

					currentFragment = SearchFragment
							.newInstance(getString(R.string.title_search));
					Bundle bundle = currentFragment.getArguments();
					bundle.putString("basePath", basePath);
					bundle.putParcelableArrayList("prefList", prefList);
					break;
				case SETTINGS_FRAGMENT:
					if (server_available) {
						Bundle b = new Bundle();
						b.putParcelableArrayList("prefList", prefList);
						b.putParcelableArrayList("prefChecked", myPrefList);
						b.putString("title", getString(R.string.title_settings));
						b.putString("basePath", basePath);
						currentFragment = SettingsFragment.newInstance(b);
					}
					break;

				}

			} else {
				currentFragment = ErrorFragment.newInstance();
			}
			if (currentFragment != null) {
				fragmentManager.beginTransaction()
						.replace(R.id.container, currentFragment).commit();
			}
			last_position = position;
		}
	}

	/**
	 * Metodo chiamato all'atto di una rotazione.
	 * */
	@Override
	public void onSaveInstanceState(Bundle b) {
		super.onSaveInstanceState(b);
		b.putString("basePath", basePath);
	}

	/**
	 * Metodo utilizzato per il passaggio del titolo corretto della pagina da
	 * visualizzare.
	 * */
	public void onSectionAttached(String title) {
		mTitle = title;
	}

	/**
	 * Metodo di restore del titolo dell'action bar.
	 * */
	public void restoreActionBar() {
		ActionBar actionBar = getActionBar();
		actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
		actionBar.setDisplayShowTitleEnabled(true);
		actionBar.setTitle(mTitle);
	}

	/**
	 * Metodo richiamato all'atto della pressione del tasto "back".
	 * */
	@Override
	public void onBackPressed() {
		if (!backButtonPressed) {
			toast = Toast.makeText(this, getResources()
					.getString(R.string.exit), Toast.LENGTH_SHORT);
			toast.show();
			backButtonPressed = true;
		} else {
			toast.cancel();
			finish();
		}
		new Thread(new Runnable() {

			@Override
			public void run() {
				Looper.prepare();
				CountDownTimer countDown = new MyCountDownTimer(3000, 500);
				countDown.start();
				Looper.loop();
			}

		}).start();
	}

	/**
	 * Metodo di creazione delle varie chiamate del menu.
	 * */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		restoreActionBar();
		if (!mNavigationDrawerFragment.isDrawerOpen()) {

			getMenuInflater().inflate(R.menu.main, menu);
			return true;
		}
		return super.onCreateOptionsMenu(menu);
	}

	/**
	 * Medodo richiamato all'atto della selezione di una delle voci del menu.
	 * */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {

		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

	/**
	 * Metodo di set della lista di preferenze relative ai film selezionati
	 * dall'utente.
	 * */
	public void setPrefChecked(ArrayList<ParcelableMovieType> prefChecked) {
		this.myPrefList = prefChecked;
	}

	/**
	 * Metodo che controlla se il server � online o meno.
	 * */
	public void onConnected() {
		try {
			server_available = new LoadSettings().execute(username).get();
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}
		onNavigationDrawerItemSelected(last_position);
	}

	/**
	 * Classe richiamata dalla onConnected() che controlla se il server �
	 * online o meno.
	 * */
	private class LoadSettings extends AsyncTask<String, Void, Boolean> {
		/**
		 * Dialog visualizzato in attesa del compimento delle operazioni in
		 * background.
		 * */
		private ProgressDialog dialog = new ProgressDialog(MainActivity.this);

		/**
		 * Codici della risposta HTTP ricevuta dal server.
		 * */
		int errorGetPrefsMessage, errorGetGenresMessage;

		/**
		 * Metodo che viene richiamato prima della chiamata a
		 * doInBackground(Params...)
		 * */
		protected void onPreExecute() {
			super.onPreExecute();
			dialog.setMessage(getResources().getString(R.string.wait));
			dialog.show();
			dialog.setCancelable(false);
		}

		/**
		 * Metodo che fa la chiamata al server in background, e attende la
		 * risposta
		 * */
		protected Boolean doInBackground(String... username) {

			// Load genres list
			HandleConnection connectionRequest = new HandleConnection(basePath,
					"MiviaMovieServer/rest/movies/genres",
					OperationEnum.GET_GENRES);

			errorGetGenresMessage = connectionRequest.doGet();

			prefList = (ArrayList<ParcelableMovieType>) connectionRequest
					.getArrayList();

			if (myPrefList == null && errorGetGenresMessage == 200) {
				String relPath = "MiviaMovieServer/rest/users/" + username[0]
						+ "/genres";
				// Load user preferences
				connectionRequest = new HandleConnection(basePath, relPath,
						OperationEnum.GET_USER_GENRES);

				errorGetPrefsMessage = connectionRequest.doGet();


				myPrefList = (ArrayList<ParcelableMovieType>) connectionRequest
						.getArrayList();

			} else {
				errorGetPrefsMessage = 200;
			}

			if (errorGetGenresMessage == 200 && errorGetPrefsMessage == 200)
				return true;
			else
				return false;
		}

		/**
		 * Metodo che viene richiamato dopo la chiamata a
		 * doInBackground(Params...)
		 * */
		protected void onPostExecute(Boolean done) {
			dialog.dismiss();
			if (!done) {
				if (errorGetPrefsMessage == 404) {
					toast = Toast.makeText(ctx,
							getResources().getString(R.string.unknown_user),
							Toast.LENGTH_SHORT);
					toast.show();
				} else {
					toast = Toast.makeText(ctx,
							getResources().getString(R.string.server_error),
							Toast.LENGTH_SHORT);
					toast.show();
				}
			}
		}
	}

	/**
	 * Classe che implementa un timer di countdown per gestire l'eventuale
	 * pressione due volte del tasto "back".
	 * */
	public class MyCountDownTimer extends CountDownTimer {

		public MyCountDownTimer(long startTime, long interval) {
			super(startTime, interval);
		}

		@Override
		public void onFinish() {
			backButtonPressed = false;
		}

		@Override
		public void onTick(long millisUntilFinished) {
		}

	}

}
